/* jshint esversion: 6 */
/*jshint -W069 */

//未在此文件中引入的对象： fs, convert,  ColorDif, logger, tipHeader

var getE00 = new ColorDif(); //CIE DE 2000色差函数

//生成地图画
module.exports = function getPixelsMap(err, pixels, imgFileName, thisClient){
	if(err) {
		logger.error("Bad image path");
		return;
	}
	let preview = false; // 像素画生成预览
	var CIELAB = thisClient.mapcolor; // 地图色方块对照表
	let width = pixels.shape[0]; // 像素画宽度
	let height = pixels.shape[1];// 像素画高度
	
	let blockArry = Array(width).fill(0).map(x => Array(height).fill(0)); // 像素方块index二维数组
	let colorArry = Array(width).fill(0).map(x => Array(height).fill(0)); // 像素rgb颜色二维数组 用于生成预览
	
	//图片读取，寻找像素方块index
	thisClient.tasking = true;
	thisClient.progress = 0;
	let pixelsNum = 0;
	for (let w = 0; w < width; w++){
		for (let h = 0; h < height; h++){
			if (thisClient.tasking == false){
				thisClient.progress = 0;
				return;
			}

			let lab = convert.rgb.lab.raw([pixels.get(w,h,0), pixels.get(w,h,1), pixels.get(w,h,2)]);
			blockArry[w][h] = getSimilarBlock(lab, CIELAB);
			if (preview == true){
				colorArry[w][h] = getSimilarColor(lab, CIELAB);
			}
			//logger.debug(`progress: [${w}, ${h}] ${getSimilarBlock(lab)}`);
			pixelsNum++;
			thisClient.progress = ((pixelsNum/(width*height))*100).toFixed(2);
			
		}
	}
	if (preview == true){
		fs.writeFile(`./.img/colorArry.txt`, JSON.stringify(colorArry), {flag:"w"}, (err) => {
			if (err) {
	    		console.error(err);
			}
		});
	}
	thisClient.progress = 0;
	thisClient.tasking = false;
	// fs.writeFile(`./.img/blockArry.txt`, JSON.stringify(blockArry), {flag:"w"}, (err) => {
		// if (err) {
			// console.error(err);
		// }
	// });
	
	//至此计算出 blockArry: 像素矩阵，值为方块索引
	

	//获取 mcfunction, 根据方块索引矩阵
	let mcfunction;		
	if (thisClient.mapcolor[0].lumingness != undefined){
		mcfunction = getMcFunc(blockArry, "uneven", thisClient);  //{func: chunkMcFunc(), maxY:maxY, minY:minY}
		thisClient.sendText(`${tipHeader} §e生成位置: §r${mcfunction.vol}`);
		if (mcfunction.maxY > 320){
			thisClient.sendText(`${tipHeader} §c生成失败, 生成高度为${mcfunction.maxY}(高于最大高度320)`);
			return;
		}
		if (mcfunction.minY < -60){
			thisClient.sendText(`${tipHeader} §c生成失败, 生成高度为${mcfunction.minY}(低于最小高度-60)`);
			return;
		}
		thisClient.sendText(`${tipHeader} §e开始生成: §r最高: ${mcfunction.maxY} | 最低: §r${mcfunction.minY}`);
			
	}else{
		mcfunction = getMcFunc(blockArry, "flat", CIELAB, thisClient);  //{func: chunkMcFunc(), maxY:maxY, minY:minY}
		thisClient.sendText(`${tipHeader} §e生成位置: §r${mcfunction.vol}`);
	}

	//客户端循环执行 mcfunction 放置方块，生成像素画
	thisClient.tasking = true;
	logger.info(`<${thisClient.name}> 正在生成像素画`);
	thisClient.runFunction(mcfunction.func,1).then(
		function(value) {thisClient.sendText(`${tipHeader} 命令执行完毕`);},
		function(error) {logger.error(error);}
	); //delay: 1
};




// 根据blockArry 返回.mcfunction
function getMcFunc(blockArry, mode, CIELAB, thisClient){
	let ChunkStep = thisClient.ChunkStep;
	let width = blockArry.length; // 像素画宽度
	let height = blockArry[0].length;// 像素画高度

	let locx = thisClient.locPos.x;
	let locy = thisClient.locPos.y;
	let locz = thisClient.locPos.z;
	let maxY = locy;
	let minY = locy;
	let mcfunction = chunkMcFunc();
	return {func: mcfunction, maxY:maxY, minY:minY, vol: `${locx} ${minY} ${locz} - ${locx+width-1} ${maxY} ${locz+height-1}`};
	

	//32*32区块分割生成
	function chunkMcFunc(){
		let mcfunction = [];
		let set_y; //像素矩阵，值为该方块的y值
		if (mode == "uneven"){
			set_y = Array(width).fill(0).map(x => Array(height+1).fill(0)); //z(h)方向多一行，用作基准
			mcfunction.push(`fill ${locx} ${locy} ${locz-1} ${locx+width-1} ${locy} ${locz-1} minecraft:snow 0`);
			for (let i =0; i< set_y.length; i++){
				set_y[i][0] = locy;
			}
		}

		/*
			地图方向
			 width
			  ——> x(w)
	   height|
			 Z
			(h)
		*/

		let chunkwidth = Math.ceil(width/ChunkStep);  //宽区块分割份数
		let chunkheight = Math.ceil(height/ChunkStep);  //高区块数分割份数

		// 区块循环
		for (let chunkw = 0; chunkw < chunkwidth; chunkw ++){
			for (let chunkh = 0; chunkh < chunkheight; chunkh++){

				//计算区块结束索引
				let wEnd, hEnd;
				if (chunkw != chunkwidth - 1){
					wEnd = chunkw*ChunkStep+ChunkStep;
				}else{
					wEnd = width;
				}

				if (chunkh != chunkheight - 1){
					hEnd = chunkh*ChunkStep+ChunkStep;
				}else{
					hEnd = height;
				}
				
				// 当前区块开始生成
				mcfunction.push(`execute at @s as @s run tp @s ${locx+(chunkw*ChunkStep+wEnd)/2} ~ ${locz+(chunkh*ChunkStep+hEnd)/2} facing ${locx+(chunkw*ChunkStep+wEnd)/2} ${locy}  ${locz+(chunkh*ChunkStep+hEnd)/2}`);
				mcfunction.push(`tickingarea remove paint`);
				mcfunction.push(`delay 1000`);
				mcfunction.push(`tickingarea add ${locx+chunkw*ChunkStep} ~ ${locz+chunkh*ChunkStep} ${locx+wEnd-1} ~ ${locz+hEnd-1} paint`);
				mcfunction.push(`delay 2000`); // 等待区块加载
				

				// 区块内循环生成
				for (let w = chunkw*ChunkStep; w < wEnd; w++){
					for (let h = chunkh*ChunkStep; h < hEnd; h++){

						//立体像素画
						if (mode == "uneven"){
							let y = set_y[w][h] + get_delta_y(isOdd(w), isOdd(h), CIELAB[blockArry[w][h]].lumingness);
							if (y > maxY){maxY = y;}
							if (y < minY){minY = y;}
							set_y[w][h+1] = y; //将当前位置y值记录进像素矩阵
							mcfunction.push(`setblock ${locx+w} ${y} ${locz+h} minecraft:${CIELAB[blockArry[w][h]].name} ${CIELAB[blockArry[w][h]].data}`);
						}

						//平面像素画
						else{
							let skip_h = h;
							for(let i = h; i<hEnd; i++){
								if (blockArry[w][i] == blockArry[w][h]){
									skip_h = i; // 相同方块
								}else{
									break;
								}
							}
							if (skip_h == h){
								mcfunction.push(`setblock ${locx+w} ${locy} ${locz+h} minecraft:${CIELAB[blockArry[w][h]].name} ${CIELAB[blockArry[w][h]].data}`);
							}else{		
								mcfunction.push(`fill ${locx+w} ${locy} ${locz+h} ${locx+w} ${locy} ${locz+skip_h} minecraft:${CIELAB[blockArry[w][h]].name} ${CIELAB[blockArry[w][h]].data}` );									
								h = skip_h;
							}

						}								
						//thisClient.progress = ((setblockNum/(width*height))*100).toFixed(2);		
						//await delay(1);
					}
				}
				//f(`[${chunkw}, ${chunkh}] compeleted!`);
			}
		} 

		//thisClient.progress = 0;
		mcfunction.push(`tickingarea remove paint`);
		thisClient.sendText(`${tipHeader} §a图片处理完毕`);
		return mcfunction;
	}	
}


//写入多个.mcfunction 文件
function runFunction(mcfunc, thisClient){
	let totalNum = mcfunc.length;
	let content = ``;
	let compeleted = 0;
	logger.info("command num: " + totalNum);
	for (let i = 0; i<totalNum; i++){
		if (mcfunc[i].split(" ")[0] == "delay"){
			continue;
		}
		content += mcfunc[i]+"\n";
		if (i >= (9999 + compeleted*10000) || i == (totalNum -1)){
			logger.info("num: "+i);
			//fs.writeSync(fs.openSync(`./.img/PixelsPlot_${compeleted}.mcfunction`, "w"), content);
			fs.writeFile(`.img/PixelsPlot_${compeleted}.mcfunction`, content, {flag:"w"}, (err) => {
				if (err) {
		    		console.error(err);
				}
			});
			content = "";
			compeleted ++;
		}
	}
	thisClient.sendText(`${tipHeader} §e写入mcfunction文件完毕`);
}



// 获取与lab色最近的方块index
function getSimilarBlock(lab, CIELAB){
	let similars = {};//{"E00":对应的方块index}
	let similar = [];
	for (let bl = 0; bl < CIELAB.length; bl++){
		let deltaE = getE00.delta_E00(lab, CIELAB[bl].color);
		similars[deltaE] = bl;
		similar.push(deltaE);
	}
	//similar.sort(function(a,b){return a-b;});
	return similars[String(arrMin(similar))];
}

// 测试：获取与lab色最近的lab 颜色list
function getSimilarColor(lab, CIELAB){
	let similars = {};//{"E00":对应的颜色list}
	let similar = [];
	for (let bl = 0; bl < CIELAB.length; bl++){
		let deltaE = getE00.delta_E00(lab, CIELAB[bl].color);
		similars[deltaE] = convert.lab.rgb(CIELAB[bl].color);
		similar.push(deltaE);
	}
	//similar.sort(function(a,b){return a-b;});
	return similars[String(arrMin(similar))];
}

//================================================
// 数学处理函数



// （x奇偶性，z奇偶性，光强）=> 相对于-z方向方块的y值
/*
	地图方向
	 ——> x
	|
	Z
*/
function get_delta_y(x_isOdd, z_isOdd, light){
    let isOdd_str = Number(x_isOdd).toString() + Number(z_isOdd).toString() + light;
    switch(isOdd_str) {
        case '00dark':
            return -1;
        case '00bright':
            return 2;
        case '01dark':
            return -2;
        case '01bright':
            return 1;
        case '10dark':
            return -2;
        case "10bright":
            return 1;
        case "11dark":
            return -1;
        case "11bright":
            return 2;
        default:
            return 0;
    }
}


// 寻找数组最小值
function arrMin(arr) {
    let len = arr.length;
    let min = Infinity;
    while (len--) {
        if (arr[len] < min) {
            min = arr[len];
        }
    }
    return min;
}


// 判断奇偶性 奇数为true
function isOdd(num) {
	let result;
    if (num % 2 != 0 ){
        result = true;
    }else{
        result = false;
    }
    return result;
}